#include "gesturerecognition.h"

GestureRecognition::GestureRecognition(QObject *parent) : QObject(parent)
{

}

GestureRecognition::GestureRecognition(int idNum, int startXVal, int startYVal, int widthVal, int heightVal, QObject *parent) :
    QObject(parent)
{
    id = idNum;
    startX = startXVal;
    startY = startYVal;
    width = widthVal;
    height = heightVal;

    pixelDif = 0;
    framesToSkip = 0;
    currentFramesProcessed = 0;
    averagePixelDif = 0;
    //we only emit a gesture detected signal if the frames are different for more than a few frames. This counts that.
    consecutiveDetections = 0;
    //sensitivity of the gesture recogniser. (recommended 2, range is 1 - 5)
    sensitivity = 2;

    //the minimum number of frames processed before we check for gestures
    //(so that we have an accurate average to work from)
    minFramesProcessed = 30;

    recognitionArea = QImage(width, height, QImage::Format_RGB32)    ;
}

//gets the next frame and calculates the difference (pixelwise) from the last stored image.
void GestureRecognition::nextFrame(IplImage *image)
{
    unsigned char redPix, greenPix, bluePix;

    //go through the image recognition area using an index (since its a liner area)
    int index = 0;
    for(int y = startY; y < startY + height; y++)
    {
        //index is the (width of the image) * the (number of vertical lines down) + the (horozontal pixels till the area starts)
        index = y*image->widthStep + startX*3;
        for(int x = startX; x < startX + width; x++)
        {
            //IplImage is in the BGR format
            bluePix = image->imageData[index];
            greenPix = image->imageData[index+1];
            redPix = image->imageData[index+2];

            QColor lastPixel = recognitionArea.pixel(x-startX,y-startY);

            //keep track of the difference in pix values
            pixelDif += qAbs(bluePix - lastPixel.blue());
            pixelDif += qAbs(greenPix - lastPixel.green());
            pixelDif += qAbs(redPix - lastPixel.red());

            //now update our recognition image
            recognitionArea.setPixel(x-startX, y-startY, qRgb(redPix,greenPix,bluePix));

            index += 3;
        }
    }
}

void GestureRecognition::checkForGesture()
{    
    if(framesToSkip > 0)
    {
        pixelDif = 0;
        framesToSkip--;
    }
    else
    {
        //if we have the min number of frames processed, and the pixel difference is sufficiently greater than the average
        //then we have a possible gesture frame.
        if((currentFramesProcessed > minFramesProcessed) && (pixelDif > (unsigned int)(averagePixelDif*sensitivity)))
        {            

            if(consecutiveDetections > 2)
            {
                emit gestureDetected(id);
                consecutiveDetections = 0;
                framesToSkip = 10;
            }
            else
            {                
                consecutiveDetections++;
            }
            pixelDif = 0;
        }else
        {


            //store our latest frame's average pixel variance
            if(currentFramesProcessed < minFramesProcessed)
            {
                lastPixelDiffs[currentFramesProcessed] = pixelDif;
            }
            else
            {
                unsigned int tempFrameNum = currentFramesProcessed;
                while(tempFrameNum >= minFramesProcessed)
                {
                    tempFrameNum -= minFramesProcessed;
                }
                lastPixelDiffs[tempFrameNum] = pixelDif;
            }

            //qDebug() << "ID: "<< id << ", pixelDiff: " << pixelDif << ", Average: " << averagePixelDif;

            //reset vars for the next frame
            pixelDif = 0;
            averagePixelDif = 0;

            //calculate and store the new average
            int total = 0;
            for(unsigned int i = 0; i < minFramesProcessed; i++)
            {
                total += lastPixelDiffs[i];
            }

            averagePixelDif = total/minFramesProcessed;            

            consecutiveDetections = 0;
            currentFramesProcessed++;
        }
    }
}

int GestureRecognition::getX()
{
    return startX;
}

int GestureRecognition::getY()
{
    return startY;
}

int GestureRecognition::getWidth()
{
    return width;
}

int GestureRecognition::getHeight()
{
    return height;
}

void GestureRecognition::setSensitivity(double sens)
{
    sensitivity = sens;
}

double GestureRecognition::getSensitivity()
{
    return sensitivity;
}
